/* 
 * File:   FileCached.h
 * Author: dell
 *
 * Created on 2012年4月15日, 下午11:19
 */

#ifndef FILECACHED_H
#define	FILECACHED_H

#include "common.h"
#include <string>
#include <vector>
#include <sys/stat.h>
#include <sys/file.h>
#include "config/ServerConfig.h"
#include "config/CacheConfig.h"
#include <evhttp/resources.h>
#include <evhttp/libev.h>
#include <evhttp/SendfileIOPump.h>
#include <evhttp/RWIOPump.h>
#include <evhttp/EvNIOReader.h>
#include <evhttp/EvNIOWriter.h>
#include <evhttp/event/IEventListener.h>
#include <sys/stat.h>
#include <time.h>
#include "ProcessMessage.h"

namespace Rapid{
    
    class FileCached : protected IEventListener{
    public:
        FileCached(ServerConfig* serverConfig);
        //FileCached();
        virtual ~FileCached();

        /** 检查文件是否在cache中 */
        bool exist(const char* filename);
        
        /** 从cache打开文件FD, 如果文件不存在，返回-1, filestat中返回文件状态 */
        FD openFile(struct stat& filestat, const char* filename);
        
        /** 存储文件 */
        bool storeFile(const char* physicalFilename);
        
        
//        /** 关闭文件,  */
//        void closeFile(const char* filename, FD fd);
        
        /** 检查此大小的文件能否被缓存 */
        bool enableCache(size_t cachedfilesize);
        
        bool enableCache(){
            return cacheConfig->existCacheConfig;
        }
        
        //清理，同步缓存文件和源始文件
        void syncCachedFiles(CacheConfig* cacheConfig);
        
        void makeSourceFileEvstats(const char* cachedbasepath);
        void newSourceFileEvstat(const char* shmfilename, long filesize);
        
        void delAllSourceFileEvstats();
        
    protected:
        virtual bool handle(const Event* e);
        bool onIOTransportEvent(IOTransportEvent* e);
    private:
        void makePhysicalFileName(std::string& physicalFileName, const char* filename);
        bool makeDirs(const char* dirname);
        //准备转送文件到缓存目录
        bool preTransportFile(std::string& shmFilename, std::string& physicalFilename);
    private:
        ServerConfig* serverConfig;
        CacheConfig* cacheConfig;
        
    private:
        typedef struct SendfileItem{
            std::string basepath;
            std::string physicalFilename;
            std::string shmFilename;
            std::string tmpShmFilename;
            FD srcfd; //源FD
            FD shmfd; //缓存文件FD
            struct stat pfilestat;
            RWIOPump* sendfile;
            IIOReader* ioreader;
            IIOWriter* iowriter;
        }SendfileItem;
        
//        typedef std::vector<SendfileItem*> SendfileItems;
//        SendfileItems sendfileItems;
        typedef hash_map<RWIOPump*, SendfileItem*, PointerHash, PointerCompare> SendfileItems;
        SendfileItems sendfileItems;
        
        typedef std::vector<RWIOPump*> DoneRWIOPumps; //已经完成的
        DoneRWIOPumps doneRWIOPumps;
        ev::async asyncClean;
        
        void asyncCallback(ev::async& async, int revents);
        void initAsyncClean();
        void startAsyncClean(RWIOPump* iopump);
        void stopAsyncClean();
        
    private:
        double cahcedCapacity; //当前容量, 单位：M
        void addCahcedCapacity(long filesize);
        
        typedef struct FileItem{
            std::string filename;
            size_t filesize;
            struct timespec atime;
        }FileItem;       
        
//        typedef struct CahcedCapacity{
//            double capacity;
//            double cahcedsize;
//        }CahcedCapacity;
//        typedef hash_map<const char*, CahcedCapacity*, __gnu_cxx::hash<const char*>, HashMapStrCompare> CahcedCapacitys;
//        CahcedCapacitys cahcedCapacitys;        
        
    public:
        static bool fileItemCompare(FileItem* ls, FileItem* rs){
            return ls->atime.tv_sec < rs->atime.tv_sec;
        }  

    private:
        long syncCachedFiles(CacheConfig* cacheConfig, std::string& filename, std::vector<FileItem*>& files);
        //返回被缓存文件的大小
        size_t handleCachedFile(CacheConfig* cacheConfig, struct stat& stat, std::string& filename, std::vector<FileItem*>& files);
        bool handleCachedFile(struct stat& stat, int basepathsize, const char* filename);
        
    private:
        //typedef std::vector<ev::stat*> SourceFileEvstats;
        //SourceFileEvstats sourceFileEvstats;
        typedef hash_map<const char*, ev::stat*, __gnu_cxx::hash<const char*>, HashMapStrCompare> SourceFileEvstats;
        SourceFileEvstats sourceFileEvstats;        
        
        typedef hash_map<const char*, char*, __gnu_cxx::hash<const char*>, HashMapStrCompare> Filenames;
        Filenames filenames;
        
        void newSourceFileEvstat(const char* cachedbasepath, const char* shmfilename);
        void delSourceFileEvstat(const char* srcfilename);
        void freeSourceFileEvstat(ev::stat* stat);
        long makeSourceFileEvstats(const char* cachedbasepath, const char*  filename);
        void statCallback(ev::stat& stat, int revents);
        
        
        
    private:
        ProcessMessage processMessage;
        
//        typedef struct FilenameMsg{
//            char basepath[100];
//            char shmfilename[200];
//        }FilenameMsg;
        
    };
}
#endif	/* FILECACHED_H */

